
#ifndef __PANELLAYER_WINDOW_H
#define __PANELLAYER_WINDOW_H

#include "MaterialEditor.h"

class MainComponent;


/** A TextButton that pops up a colour chooser to change its colours. */
class ColourChangeButton  : public TextButton,
                            public ChangeListener
{
public:
    ColourChangeButton() : TextButton ("change back ground colour...")
    {
        setSize (10, 24);
        changeWidthToFitText();
		canResetToDefault = true;
    }

    ~ColourChangeButton()
    {
    }

    void resetToDefault();
    void clicked();
    void changeListenerCallback (ChangeBroadcaster* source);


private:
    bool canResetToDefault;

    class ColourSelectorComp   : public Component,
                                 public ButtonListener
    {
    public:
        ColourSelectorComp (ColourChangeButton* owner_,
                            const bool canResetToDefault)
            : owner (owner_),
              defaultButton ("ResetToDefault")
        {
            addAndMakeVisible (&selector);
            selector.setName ("background");
            selector.setCurrentColour (g_EditorBKColor);
            selector.addChangeListener (owner);
			selector.setColour(ColourSelector::backgroundColourId, Colours::transparentBlack);

            if(canResetToDefault)
            {
                addAndMakeVisible (&defaultButton);
                defaultButton.addListener (this);
            }
        }

        void resized()
        {
            if (defaultButton.isVisible())
            {
                selector.setBounds(0, 0, getWidth(), getHeight() - 30);
                defaultButton.changeWidthToFitText(22);
                defaultButton.setTopLeftPosition(10, getHeight() - 26);
            }
            else
            {
                selector.setBounds(0, 0, getWidth(), getHeight());
            }
        }

        void buttonClicked(Button*)
        {
            owner->resetToDefault();
            selector.setCurrentColour(g_EditorBKColor);
			for(int i=0; i<24; i++)
				selector.setSwatchColour(i, g_DefaultColor[i]);
			selector.repaint();
        }

    private:
        class ColourSelectorWithSwatches : public ColourSelector
        {
        public:
            ColourSelectorWithSwatches()
            {
            }

            int getNumSwatches() const
            {
                return 24;
            }

            Colour getSwatchColour (int index) const
            {
                return g_DefaultColor[index];
            }

            void setSwatchColour (int index, const Colour& newColour) const
            {
                g_DefaultColor[index] = newColour;
            }
        };

        ColourChangeButton* owner;
        ColourSelectorWithSwatches selector;
        TextButton defaultButton;
    };
};
/////////////////////////////////////////////////////////////////////////////////////


class ColourPropertyComponent  : public PropertyComponent
{
public:
    //==============================================================================
    ColourPropertyComponent (const String& name,
							 const Colour& defaultcolour,
							 Colour*	   pcurrentcolour,
                             const bool canResetToDefault)
        : PropertyComponent (name)
    {
        addAndMakeVisible (new ColourEditorComponent(canResetToDefault, defaultcolour, pcurrentcolour));
    }

    ~ColourPropertyComponent()
    {
        deleteAllChildren();
    }
	

    void refresh()
    {
        ((ColourEditorComponent*) getChildComponent (0))->refresh();
    }

private:
	/** A EditorComponent that pops up a colour chooser to change its colours. */
	class ColourEditorComponent :	public Component,
									public ChangeListener
	{
	public:
		ColourEditorComponent (const bool canResetToDefault_, Colour DefaultColor, Colour *pCurrentCol)
			: canResetToDefault (canResetToDefault_)
		{
			m_DefaultColour = DefaultColor;
			m_pCurrentColour = pCurrentCol;
		}

		void paint (Graphics& g)
		{
			g.fillAll (Colours::grey);

			g.fillCheckerBoard (getLocalBounds().reduced (2, 2),
								10, 10,
								Colour (0xffdddddd).overlaidWith (*m_pCurrentColour),
								Colour (0xffffffff).overlaidWith (*m_pCurrentColour));

			g.setColour (Colours::white.overlaidWith (*m_pCurrentColour).contrasting());
			g.setFont (getHeight() * 0.6f);
			g.drawFittedText (m_pCurrentColour->toDisplayString (true),
							  2, 1, getWidth() - 4, getHeight() - 1,
							  Justification::centred, 1);
		}

		void resetToDefault()
		{
			g_DefaultColor[0] = Colours::blue;
			g_DefaultColor[1] = Colours::grey;
			g_DefaultColor[2] = Colours::red;
			g_DefaultColor[3] = Colours::yellow;
			g_DefaultColor[4] = Colours::aliceblue;
			g_DefaultColor[5] = Colours::antiquewhite;
			g_DefaultColor[6] = Colours::aqua;
			g_DefaultColor[7] = Colours::aquamarine;
			g_DefaultColor[8]  = Colours::azure;
			g_DefaultColor[9]  = Colours::beige;
			g_DefaultColor[10] = Colours::bisque;
			g_DefaultColor[11] = Colours::blanchedalmond;
			g_DefaultColor[12] = Colours::blueviolet;
			g_DefaultColor[13] = Colours::brown;
			g_DefaultColor[14] = Colours::burlywood;
			g_DefaultColor[15] = Colours::cadetblue;
			g_DefaultColor[16]  = Colours::chartreuse;
			g_DefaultColor[17]  = Colours::chocolate;
			g_DefaultColor[18] = Colours::coral;
			g_DefaultColor[19] = Colours::cornflowerblue;
			g_DefaultColor[20] = Colours::cornsilk;
			g_DefaultColor[21] = Colours::crimson;
			g_DefaultColor[22] = Colours::cyan;
			g_DefaultColor[23] = Colours::darkblue;
		}

		void refresh()
		{
			repaint();
		}

		void mouseDown (const MouseEvent& e)
		{
			ColourSelectorComp colourSelector (this, canResetToDefault);

			PopupMenu m;
			m.addCustomItem (1234, &colourSelector, 300, 400, false);
			m.showAt (this);
		}

		void changeListenerCallback (ChangeBroadcaster* source)
		{
			const ColourSelector* const cs = (const ColourSelector*) source;

			if( cs->getCurrentColour() != *m_pCurrentColour )
			{
				*m_pCurrentColour = cs->getCurrentColour();
				refresh();
			}
		}
	private:
		Colour *m_pCurrentColour;
		Colour m_DefaultColour;
		bool canResetToDefault;

		class ColourSelectorComp   : public Component,
									 public ButtonListener
		{
		public:
			ColourSelectorComp (ColourEditorComponent* owner_,
								const bool canResetToDefault)
				: owner (owner_),
				  defaultButton ("ResetToDefault")
			{
				addAndMakeVisible(&selector);
				selector.setName("choose colour");
				selector.setCurrentColour(*owner->m_pCurrentColour);
				selector.addChangeListener(owner);
				selector.setColour(ColourSelector::backgroundColourId, Colours::transparentBlack);

				if(canResetToDefault)
				{
					addAndMakeVisible (&defaultButton);
					defaultButton.addListener (this);
				}
			}

			void resized()
			{
				if (defaultButton.isVisible())
				{
					selector.setBounds(0, 0, getWidth(), getHeight() - 30);
					defaultButton.changeWidthToFitText(22);
					defaultButton.setTopLeftPosition(10, getHeight() - 26);
				}
				else
				{
					selector.setBounds(0, 0, getWidth(), getHeight());
				}
			}

			void buttonClicked(Button*)
			{
				owner->resetToDefault();
				selector.setCurrentColour(owner->m_DefaultColour);
				for(int i=0; i<24; i++)
					selector.setSwatchColour(i, g_DefaultColor[i]);
				selector.repaint();
			}

		private:
			class ColourSelectorWithSwatches : public ColourSelector
			{
			public:
				ColourSelectorWithSwatches()
				{
				}

				int getNumSwatches() const
				{
					return 24;
				}

				Colour getSwatchColour (int index) const
				{
					return g_DefaultColor[index];
				}

				void setSwatchColour (int index, const Colour& newColour) const
				{
					g_DefaultColor[index] = newColour;
				}
			};

			ColourEditorComponent* owner;
			ColourSelectorWithSwatches selector;
			TextButton defaultButton;
		};
	};

};

/////////////////////////////////////////////////////////////////////////////////////
class MaterialValueFloatProperty  :	public SliderPropertyComponent,
									public ChangeListener
{
public:
    MaterialValueFloatProperty (const String& name, float *pValue,
		double rangeMin, double rangeMax, double interval)
        : SliderPropertyComponent (name, rangeMin, rangeMax, interval, 1.0)

    {
		m_pValue = pValue;
    }
    ~MaterialValueFloatProperty()
    {
    }

    void setValue (double newValue)
    {
		*m_pValue = static_cast<float>(newValue);
    }

    double getValue() const
    {
		return static_cast<double>(*m_pValue);
    }

    void changeListenerCallback (ChangeBroadcaster*)
    {
        refresh();
    }
private:
	float *m_pValue;
};

class MaterialValueDWORDProperty  :	public SliderPropertyComponent,
									public ChangeListener
{
public:
    MaterialValueDWORDProperty (const String& name, DWORD *pValue,
		double rangeMin, double rangeMax, double interval)
        : SliderPropertyComponent (name, rangeMin, rangeMax, interval, 1.0)

    {
		m_pValue = pValue;
    }
    ~MaterialValueDWORDProperty()
    {
    }

    void setValue (double newValue)
    {
		*m_pValue = static_cast<DWORD>(newValue);
    }

    double getValue() const
    {
		return static_cast<double>(*m_pValue);
    }

    void changeListenerCallback (ChangeBroadcaster*)
    {
        refresh();
    }
private:
	DWORD *m_pValue;
};
/////////////////////////////////////////////////////////////////////////////////////

class MaterialChooseProperty  :		public ChoicePropertyComponent,
									public ChangeListener
{
public:
	MaterialChooseProperty(CMaterialComboxContex* _pContex) : ChoicePropertyComponent(_pContex->m_stringName)
	{
		pContex = _pContex;
		for( int i=0; i<20; i++ )
		{
			if( _pContex->m_ComboxString[i].isNotEmpty() )
				choices.add(_pContex->m_ComboxString[i]);
		}
	}

	~MaterialChooseProperty()
	{
	}

	void setIndex (int newIndex)
	{
		pContex->m_currentValue = pContex->m_ComboxValue[newIndex];
	}

	int getIndex() const
	{
		for( int i=0; i<20; i++ )
			if( pContex->m_ComboxValue[i] == pContex->m_currentValue )
				return i;
		return 0;
	}

	void changeListenerCallback (ChangeBroadcaster*)     { refresh(); }

private:
	CMaterialComboxContex*	pContex;
};

//==============================================================================
class MaterialBooleanProperty  :	public BooleanPropertyComponent,
									public ChangeListener
{
public:
	MaterialBooleanProperty(	const String& name,
								const String& onText,
								const String& offText,
								bool *pBoolValue )
    : BooleanPropertyComponent(name, onText, offText)
	{
		m_pBoolValue = pBoolValue;
	}

	~MaterialBooleanProperty()
	{
	}

	void setState(bool newState)
	{
		*m_pBoolValue = newState;
		refresh();
	}

	bool getState() const
	{
		return *m_pBoolValue;
	}

	void changeListenerCallback (ChangeBroadcaster*)
	{
		refresh();		
	}
private:
	bool* m_pBoolValue;
};
//==============================================================================
class MaterialTextureStageStateChooseProperty :	public ChoicePropertyComponent,
												public ChangeListener
{
public:
	MaterialTextureStageStateChooseProperty(DWORD _Stage, CMaterialComboxContex* _pContex) : ChoicePropertyComponent(_pContex->m_stringName)
	{
		Stage = _Stage;
		pContex = _pContex;
		for( int i=0; i<20; i++ )
		{
			if( _pContex->m_ComboxString[i].isNotEmpty() )
				choices.add(_pContex->m_ComboxString[i]);
		}
	}

	~MaterialTextureStageStateChooseProperty()
	{
	}

	void setIndex (int newIndex)
	{
		g_TextureStageState[Stage][pContex->m_currentType] = pContex->m_ComboxValue[newIndex];
	}

	int getIndex() const
	{
		for( int i=0; i<20; i++ )
			if( pContex->m_ComboxValue[i] == g_TextureStageState[Stage][pContex->m_currentType] )
				return i;
		return 0;
	}

	void changeListenerCallback (ChangeBroadcaster*)     { refresh(); }

private:
	DWORD					Stage;
	CMaterialComboxContex*	pContex;
};


/////////////////////////////////////////////////////////////////////////////////////
class ControlPanelComponent  :	public Component,
								private ChangeListener
{
public:
    //==============================================================================
    ControlPanelComponent ();
    ~ControlPanelComponent();

	void resized();
	void changeListenerCallback(ChangeBroadcaster*);
	void setTextureSampleStatePropertyComponentEnable(bool bEnable);

    //==============================================================================
    juce_UseDebuggingNewOperator

private:
    //==============================================================================
    ScopedPointer<TextButton>		m_pChangeBGColorButton;

	ScopedPointer<GroupComponent>	m_pGroupComponent;

	ScopedPointer<PropertyPanel>	m_Texture_Panel;


    //==============================================================================
    // (prevent copy constructor and operator= being generated..)
    ControlPanelComponent (const ControlPanelComponent&);
    const ControlPanelComponent& operator= (const ControlPanelComponent&);

	//==============================================================================
    class TextureNameProperty  :	public TextPropertyComponent,
									private ChangeListener
    {
    public:
        TextureNameProperty(DWORD _stage) : TextPropertyComponent("Texture Path", 256, false)
        {
			Stage = _stage;
        }

        ~TextureNameProperty()
        {
        }
        void setText (const String& newText)
		{
			if( newText.isEmpty() )
			{
				if( Stage == 0 )
				{
					g_DiffuseTexPath[0] = 0;
					g_pDevice->GetSkinManager()->AddTexture(g_DefaultSkin, g_DiffuseTexPath, Stage);
				}
				else if( Stage == 1 )
				{
					g_NormalTexPath[0] = 0;
					g_pDevice->GetSkinManager()->AddTexture(g_DefaultSkin, g_NormalTexPath, Stage);
				}
			}

		}
        String getText() const							
		{ 
			if( Stage == 0 )
				return g_DiffuseTexPath; 
			else if( Stage == 1 )
				return g_NormalTexPath;
			else
				return String::empty;
		}

        void changeListenerCallback (ChangeBroadcaster*){ refresh(); }

	private:
		DWORD Stage; 
    };
	//==============================================================================
	class TextureChooseProperty  :	public PropertyComponent,
									private ButtonListener
	{
	public:
		TextureChooseProperty(TextureNameProperty* pFileName, DWORD _stage) : PropertyComponent("Choose Texture Path")
		{
			Stage = _stage;
			pTextureFileName = pFileName;
			LastChooseFile = File::getCurrentWorkingDirectory();
			addAndMakeVisible(button = new TextButton ("Choose Texture File"));
			button->addListener(this);
			button->setTriggeredOnMouseDown(true);
			button->setConnectedEdges(TextButton::ConnectedOnLeft | TextButton::ConnectedOnRight);
		}


		void resized()
		{
			const juce::Rectangle<int> r(getLookAndFeel().getPropertyComponentContentPosition (*this));

			button->changeWidthToFitText(r.getHeight());
			button->setTopLeftPosition(r.getX(), r.getY());			
		}

		void refresh()
		{	
			pTextureFileName->refresh();
		}

		void buttonClicked(Button* buttonThatWasClicked)
		{
		    if( buttonThatWasClicked == button )
			{
				ImagePreviewComponent imagePreview;
				imagePreview.setSize (200, 200);

				FileChooser fc( "Choose an image to open...",
								LastChooseFile,
								"*.jpg;*.jpeg;*.png;*.dds;*.tga;",
								false );

				if( fc.browseForFileToOpen(&imagePreview) )
				{
					String chosen;
					chosen << fc.getResult().getFullPathName();
					LastChooseFile = fc.getResult().getParentDirectory();

					if( Stage == 0 )
					{
						_stprintf_s( g_DiffuseTexPath, chosen.toWideCharPointer() );
						g_pDevice->GetSkinManager()->AddTexture(g_DefaultSkin, g_DiffuseTexPath, Stage);
					}
					else if( Stage == 1 )
					{
						_stprintf_s( g_NormalTexPath, chosen.toWideCharPointer() );
						g_pDevice->GetSkinManager()->AddTexture(g_DefaultSkin, g_NormalTexPath, Stage);
					}					
					
					refresh();	
				}
			}				
		}

	private:
		ScopedPointer<TextButton> button;
		TextureNameProperty* pTextureFileName;
		DWORD Stage;
		juce::File LastChooseFile;
	};
	//==============================================================================
	class SampleStateChooseProperty  :	public ChoicePropertyComponent,
										public ChangeListener
	{
	public:
		SampleStateChooseProperty(DWORD _Stage, CMaterialComboxContex* _pContex) : ChoicePropertyComponent(_pContex->m_stringName)
		{
			Stage = _Stage;
			pContex = _pContex;
			for( int i=0; i<20; i++ )
			{
				if( _pContex->m_ComboxString[i].isNotEmpty() )
					choices.add(_pContex->m_ComboxString[i]);
			}
		}

		~SampleStateChooseProperty()
		{
		}

		void setIndex (int newIndex)
		{
			g_TexSampleState[Stage][pContex->m_currentType] = pContex->m_ComboxValue[newIndex];
		}

		int getIndex() const
		{
			for( int i=0; i<20; i++ )
				if( pContex->m_ComboxValue[i] == g_TexSampleState[Stage][pContex->m_currentType] )
					return i;
			return 0;
		}

		void changeListenerCallback (ChangeBroadcaster*)     { refresh(); }

	private:
		DWORD					Stage;
		CMaterialComboxContex*	pContex;
	};
};


/////////////////////////////////////////////////////////////////////////////////////

class MaterialPreviewPage   :	public Component,
								public ComboBoxListener
{
public:
    MaterialPreviewPage(MainComponent *pMainComp);
	~MaterialPreviewPage();
    void resized();
    void comboBoxChanged(ComboBox* comboBoxThatHasChanged);
	void visibilityChanged(); 

   //==============================================================================
    juce_UseDebuggingNewOperator

private:
    ScopedPointer<ComboBox>		m_pMaterialInfoComboBox;
    ScopedPointer<Label>		m_pMaterialInfoLabel;
	MainComponent*				m_pMainComponent;

    //==============================================================================
    // (prevent copy constructor and operator= being generated..)
    MaterialPreviewPage (const MaterialPreviewPage&);
    const MaterialPreviewPage& operator= (const MaterialPreviewPage&);
};

/////////////////////////////////////////////////////////////////////////////////////


class MaterialCustomPage  :	public Component,
							public ButtonListener,
							private ChangeListener
{
public:
    MaterialCustomPage(MainComponent *pMainComp);
	~MaterialCustomPage();
    void resized();
	void changeListenerCallback(ChangeBroadcaster*);
	void buttonClicked(Button* button);
	void visibilityChanged();
   //==============================================================================
    juce_UseDebuggingNewOperator

private:
	ScopedPointer<TextButton>		m_pResetButton;
	ScopedPointer<PropertyPanel>	m_Custom_Panel;
	MainComponent*					m_pMainComponent;
    //==============================================================================
    // (prevent copy constructor and operator= being generated..)
    MaterialCustomPage (const MaterialCustomPage&);
    const MaterialCustomPage& operator= (const MaterialCustomPage&);
};

/////////////////////////////////////////////////////////////////////////////////////
class SourceCodePage :  public Component						
{
public:
    SourceCodePage(MainComponent *pMainComp);
	~SourceCodePage();
    void resized();
	void visibilityChanged();


   //==============================================================================
    juce_UseDebuggingNewOperator

private:
	ScopedPointer<TextEditor>		m_SourceEditor;
	MainComponent*					m_pMainComponent;
    //==============================================================================
    // (prevent copy constructor and operator= being generated..)
    SourceCodePage (const SourceCodePage&);
    const SourceCodePage& operator= (const SourceCodePage&);

};



/////////////////////////////////////////////////////////////////////////////////////

class MaterialEditorSplashScreen :	public SplashScreen
{
public:
	MaterialEditorSplashScreen() 
		: splash_screen( ImageCache::getFromMemory(BinaryData::SplashScreen_jpg, BinaryData::SplashScreen_jpgSize) )
	{
		splash_screen_text.setJustification(Justification::centred);
        splash_screen_text.append(L"OyEngine's Material Editor", Font (18.0f, Font::plain), Colours::white);
		
	}
	~MaterialEditorSplashScreen() {}

	int getWidth()		{ return splash_screen.getWidth(); }
	int getHeight()		{ return splash_screen.getHeight(); }

	void paint( Graphics & g )
	{
        g.drawImageWithin(splash_screen, 0, 0, getWidth(), getHeight(),
                           RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize,
                           false);

        splash_screen_text.draw(g, juce::Rectangle<int>(0, getHeight()-80, getWidth(), 100).toFloat());
	}


private:
	Image splash_screen;
    AttributedString splash_screen_text;
};
/////////////////////////////////////////////////////////////////////////////////////

#endif